我們在前面幾章知道 this 會依據呼叫方式印出不同結果,那如果我們希望可以存取 this 的某個特定內容呢?要指定 this 取得其內容有幾種方法:
//來個範例!
//記得用回推的方式看會比較清楚
function callName() {
console.log('區域', this.name); //這裡會印出區域結果
var that = this; //讓that變數 = this 在被呼叫時間點的值
setTimeout(function () {
console.log('全域', this.name);
//上一章我們提過,這裡會從全域(Window)去尋找
console.log('區域', that.name);
// 因為我們已經指定 that,所以只會去尋找被呼叫時間點的值
}, 10);
}
var name = '全域阿婆'; //全域(Window)
var auntie = { //區域(這裡的 function 指向全域的 function,但不重要)
name: '漂亮阿姨',
callName: callName
}
auntie.callName();
//我們呼叫 auntie 裡的 callName,
//callName = function callName,所以他將會印出以下三行的結果:
//console.log('區域', this.name);
//console.log('全域', this.name);
//console.log('區域', that.name);
//////////////解析一下
**//第一個:console.log('區域', this.name);
//印出: 區域 漂亮阿姨**
//我們將這裡的 this.name 回推,往外看 第一個先看到 function callName
//function callName 是 var auntie 裡的物件 callName: callName
//所以這裡的 this是指向 auntie ,而 auntie裡的name是 漂亮阿姨
//故就會印出 區域 漂亮阿姨
**//第二個:console.log('全域', this.name);
//印出: 全域 全域阿婆**
//一樣我們將這裡的 this.name 回推, setTimeout(function ()
//是切分變數的最小範圍(也就是scope),故this 往外推的時候指向全域(window)
//所以他會找到的是 var name = '全域阿婆';
//故印出 全域 全域阿婆
//**第三個:console.log('區域',** that.name**);
//印出: 區域 漂亮阿姨**
//我們在 function callName() 中指定 var that = this;
//記得我們是以 auntie.callName();的方式呼叫的
//所以結果就會跟 第一個 一樣
如果你看懂上面了,應該會想說 that 一定要寫 that 嗎?
其實並不用,這裡的變數名稱可以自己指定,例如一般常用的 a 或其他自訂名稱都可以。
var that = this ;
//that可以替換成任意的自訂名稱
有三個方式可以使用,分別是 bind() / call() / apply()
.bind()
產生副本,藉由副本讀取資料
//來個範例吧!
var obj = {
x : 123,
}
//obj物件中,x的值是123
var func = function(){
console.log(this.x);
}
func(); //這裡我們嚴格指定 var func = function(),故 undefiend
func.bind(obj); //當我們使用 .bind(obj),會替我們將 this 指向 obj ,故得123
.call()
.call() 調用的函式可以直接傳入新的物件,使其作為 this 所指向的物件。
//來個範例吧!
var name = '全域阿婆';
function callName() {
console.log(this.name);
}
callName();
// 去尋找了全域,故印出'全域阿婆'
callName.call({name: '漂亮阿姨'});
// 這邊直接將this指向'漂亮阿姨','漂亮阿姨'作為物件被傳入 callName 中
.apply()
.apply() 調用的函式可以直接傳入新的物件,使其作為 this 所指向的物件。
var name = '全域阿婆';
function callName() {
console.log(this.name);
}
callName();
// 去尋找了全域,故印出'全域阿婆'
callName.apply({name: '漂亮阿姨'});
// 這邊直接將this指向'漂亮阿姨','漂亮阿姨'作為物件被傳入 callName 中
....等等,先聽我解釋!(鼻要打臉)
//來個範例吧!
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {
a: 1,
b: 3
};
add.call(o, 5, 7); // 16
// 第一個參數(parameter)是調用了 this 的物件,
// 後續參數(parameters)會作為函式呼叫內的參數(arguments)而通過
add.apply(o, [10, 20]); // 34
// 第一個參數(parameter)是調用了 this 的物件,
// 第二個參數的陣列作為函式呼叫內的參數(arguments)之構件
.call() 和 .apply() 的區別就在於傳入的方式,.call()傳入參數的方式是以 『 , 』隔開,而 .apply() 則是傳入整個陣列作為參數。
bind(綑綁)
產生副本,藉由副本讀取資料。
bind 會在呼叫前就先綁定某個物件(類似產生副本),讓他不管怎麼呼叫都有固定的 this。
call (呼叫)/ apply(應用)
使用在 context 時常變動的場景(例如上面的範例 o 就是 context ),依照呼叫時需要帶入不同物件作為該 function 的 this ,在呼叫下就立即執行。
引用及參考資訊
鐵人賽:JavaScript 的 this 到底是誰?
淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
What's THIS in JavaScript ? [上]